<?php
class ti_query_builder
{
	function __construct()
	{
		$this->type    = null;
		$this->fields  = array(); # 
		$this->tables  = array(); #only select has more than one entry
		$this->wheres  = array(); #used by select, update, delete
		$this->joins   = array(); #used by select, update, delete
		$this->sets    = array(); #only used by update type
		$this->values  = array(); #only used by insert type
		$this->urlset  = array();
		$this->urlwhere= array();
		$this->sorts   = array();
		$this->limit   = null;
		$this->offset  = null;
		$this->same_user = false;
	}
	
	function select()
	{
		$this->type = 'select';
		$tables = func_get_args();
		foreach($tables as $table)
		{
			$this->tables[] = $table;
		}
		return $this;
	}
	
	function update($table)
	{
		$this->type = 'update';
		$this->tables[0] = $table;
		return $this;
	}

	function insert($table)
	{
		$this->type = 'insert';
		$this->tables[0] = $table;
		return $this;
	}	
	
	function delete($table)
	{
		$this->type = 'delete';
		$this->tables[0] = $table;
		return $this;
	}	
	
	function fields()
	{
		$fields = func_get_args();
		if(count($fields) == 0)
		{
			$this->fields[] = '*';
		}
		else
		{
			for ($i = 0; $i < count($fields); $i++)
			{
				$this->fields[] = $fields[$i];
			}
		}
		return $this;
	}
		
	
	function ljoin($join_table,$col1,$col2=null)
	{
		$this->join('left',$join_table,$col1,$col2);
		return $this;
	}
	
	function rjoin($join_table,$col1,$col2=null)
	{
		$this->join('left',$join_table,$col1,$col2);
		return $this;
	}
	
	function join($direction='inner',$join_table,$col1,$col2=null)
	{
		$join = ' '.$direction.' join '.$join_table.' ';
		if(is_null($col2))
		{
			$join .= ' using('.$col1.')';
		}
		else
		{
			$join .= ' on '.$col1.'='.$col2;
		}
		$this->joins[] = $join;
		return $this;
	}
		
	function sort($new_col,$dir='')
	{
		array_unshift($this->sorts,($new_col. (($dir=='' || $dir=='asc')?'':' desc')));
		return $this;
	}
	
	function limit($new)
	{
		$this->limit = $new;
		return $this;
	}
	
	function offset($new)
	{
		$this->offset = $new;
		return $this;
	}
	
	function page($page_offset,$limit=null)
	{
		$this->limit($limit);
		if($page_offset > 0)
			$this->offset($page_offset * $limit);
		return $this;
	}
	
	function where($field,$value=null)
	{
		global $ti;
		if(is_null($value))
		{
			$this->wheres[] = $field.'={'.$field.'}';
		}
		else if($value == 'null')
		{
			$this->wheres[] = $field.' is null';
		}
		else
		{
			$this->wheres[] = $field.='=\''.$ti->config['database.escape']($value).'\'';
		}
		return $this;
	}
	
	function dset()
	{
		global $ti;
		$args = func_get_args();
		foreach($args as $arg)
		{
			$this->urlset[] = $arg;
		}
		return $this;
	}
	
	function dwhere()
	{
		global $ti;
		$args = func_get_args();
		foreach($args as $arg)
		{
			$this->urlwhere[] = $arg;
		}
		return $this;
	}
	
	function same_user()
	{
		global $ti;
		$this->same_user = true;
	}
	
	function session($db_field,$session_field=null)
	{
		global $ti;
		$session_field = (is_null($session_field))?$db_field:$session_field;
		$this->where($db_field,$ti->session[$session_field]);
		return $this;
	}
	
	function set($field,$value=null)
	{
		global $ti;
		if($this->type == 'insert')
		{
			if(is_null($value))
			{
				$this->fields[] = $field;
				$this->values[] = '{'.$field.'}';
			}
			else
			{
				$this->fields[] = $field;
				if($value === false)
				{
					$this->values[] = 'null';
				}
				else
				{
					$this->values[] = '\''.$ti->config['database.escape']($value).'\'';
				}
			}
		}
		else
		{
			if(is_null($value))
			{
				$this->sets[] = $field.'={'.$field.'}';
			}
			else
			{
				if($value === false)
				{
					$this->sets[] = $field.='=null';
				}
				else
				{
					$this->sets[] = $field.='=\''.$ti->config['database.escape']($value).'\'';
				}
			}
		}
		return $this;
	}	
	
	function row_count($data=null)
	{
		global $ti;
		$newquery = clone $this;
		$newquery->count_sql  = '';
		
		$field = (count($newquery->fields) == 0)?'*':$newquery->fields[0];
	
		$newquery->count_sql .= 'select count('.$field.') as row_count ';
		$newquery->count_sql .= ' from ';
		$newquery->count_sql .= implode("\n",$newquery->tables);
		if(count($newquery->wheres) > 0)
		{
			$newquery->count_sql .= 	' where ';
			$newquery->count_sql .= implode(' and ',$newquery->wheres);
		}
		$query = new ti_query($newquery->count_sql);
		$query->next($data);
		return $query->data['row_count'];
	}
	
	function execute($data=null)
	{
		global $ti;
		$final_sql = $this->finalize();
		
		$query = new ti_query($final_sql);
		$query->execute($data);
		return $query;
	}
	
	function next($data=null)
	{
		if(!$this->query)
		{
			$this->query = $this->execute($data);
			$this->data =& $this->query->data;
			$this->loop_style =& $this->query->loop_style;
			$this->loop_count =& $this->query->loop_count;
		}
		return $this->query->next();
	}
	
	function finalize()
	{
		global $ti;
		
		$newquery = clone $this;
		
		$newquery->final_sql = '';
		
		if($newquery->type == 'select' && count($newquery->fields) == 0)
		{
			$newquery->fields[] = '*';
		}
		
		if($newquery->same_user)
		{
			$user_id = intval($ti->session[$ti->config['var.session_user_id']]);
			if($user_id < 1)
			{
				throw new Exception('Invalid User ID');
			}
			$newquery->where($ti->config['var.db_user_id'],$user_id);
		}
		
		foreach($newquery->urlset as $key=>$value)
		{
			if(is_null($ti->data[$value]) || empty($ti->data[$value]) || $ti->data[$value].'' == '')
			{
				$newquery->set($value,false);
			}
			else
			{
				$newquery->set($value,$ti->data[$value]);
			}
		}
		
		foreach($newquery->urlwhere as $key=>$value)
		{
			if(is_null($ti->data[$value]) || empty($ti->data[$value]) || $ti->data[$value].'' == '')
			{
				$newquery->where($value,false);
			}
			else
			{
				$newquery->where($value,$ti->data[$value]);
			}
		}
		
		switch($newquery->type)
		{
			case 'select':
				$newquery->final_sql .= 'select '.implode(',',$newquery->fields).' ';
				$newquery->final_sql .= ' from ';
				$newquery->final_sql .= implode("\n",$newquery->tables);
				$newquery->final_sql .= implode("\n",$newquery->joins);
				if(count($newquery->wheres) > 0)
				{
					$newquery->final_sql .= 	' where ';
					$newquery->final_sql .= implode(' and ',$newquery->wheres);
				}
				
				if(count($newquery->sorts) > 0)
				{
					$newquery->final_sql .= ' order by ';
					$newquery->final_sql .= implode(',',$newquery->sorts);
				}

				if(!is_null($newquery->limit))
				{
					$newquery->final_sql .= ' limit '.$newquery->limit;
				}
				
				if(!is_null($newquery->offset))
				{
					$newquery->final_sql .= ' offset '.$newquery->offset;
				}

				break;
			case 'update':
				$newquery->final_sql .= 'update '.$newquery->tables[0] .' set ';
				$newquery->final_sql .= implode(',',$newquery->sets);
				if(count($newquery->wheres) > 0)
				{
					$newquery->final_sql .= 	' where ';
					$newquery->final_sql .= implode(' and ',$newquery->wheres);
				}
				break;
			case 'insert':
				$newquery->final_sql .= 'insert into '.$newquery->tables[0];
				$newquery->final_sql .= '('.implode(',',$newquery->fields).') values ';
				$newquery->final_sql .= '('.implode(',',$newquery->values).');';
				break;
			case 'delete':
				$newquery->final_sql .= 'delete from '.$newquery->tables[0] .' ';
				if(count($newquery->wheres) > 0)
				{
					$newquery->final_sql .= 	' where ';
					$newquery->final_sql .= implode(' and ',$newquery->wheres);
				}
				break;
		}
		return $newquery->final_sql;
	}
	
	function num_rows()
	{
		return $this->query->num_rows();
	}
}

?>